﻿using System;
using System.IO;
using System.Data;
using System.Drawing;
using System.Data.OleDb;
using System.Collections.Generic;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Carto;
using PlanningGIS.Util;

namespace PlanningGIS.ArcGIS
{
    /// <summary>
    /// 作用：Symbol操作类
    /// </summary>
    public class SymbolHelper
    {
        /// <summary>
        /// 得到相应的符号
        /// </summary>
        /// <param name="styletype">符号类型</param>
        /// <param name="stylefile">符号相对位置</param>
        public static List<SymbolItem> GetStyles(zjgisStyleGalleryType styletype, string stylefile)
        {
            List<SymbolItem> list = new List<SymbolItem>();
            if (string.IsNullOrWhiteSpace(stylefile) || !File.Exists(stylefile)) return list;
            try
            {
                using (OleDbConnection cnn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data source= " + stylefile))
                {
                    string sql = "SELECT * FROM [" + styletype.GetDescription() + "] ";
                    //if (!string.IsNullOrWhiteSpace(category)) cmdText += " Where Category = '" + category + "'";
                    //cmdText += " order by Name ";
                    IDbDataAdapter pAdp = new OleDbDataAdapter(sql, cnn);
                    DataSet dataset = new DataSet();
                    pAdp.Fill(dataset);
                    IPersistStream persistStream = null;
                    if (dataset.Tables.Count > 0)
                    {
                        foreach (DataRow dr in dataset.Tables[0].Rows)
                        {
                            System.Array arr = (System.Array)dr["Object"];
                            int count = arr.Length - 16;
                            byte[] bytes = new byte[16];
                            for (int j = 0; j < 16; j++)
                            {
                                bytes[j] = (byte)arr.GetValue(j);
                            }
                            Guid guid = new Guid(bytes);
                            //由Guid创建Style对象
                            persistStream = (IPersistStream)Activator.CreateInstance(Type.GetTypeFromCLSID(guid));
                            byte[] data = new byte[count];
                            for (int j = 0; j < count; j++)
                            {
                                data[j] = (byte)arr.GetValue(j + 16);
                            }
                            IMemoryBlobStream stream = new MemoryBlobStream();
                            ((IMemoryBlobStreamVariant)stream).ImportFromVariant(data);
                            persistStream.Load((IStream)stream);
                            SymbolItem symbolItem = new SymbolItem()
                            {
                                Symbol = persistStream,
                                Name = dr["Name"].ToString(),
                                Category = dr["Category"].ToString()
                            };
                            list.Add(symbolItem);
                        }
                    }
                    cnn.Close();
                    cnn.Dispose();
                }
            }
            catch
            {

            }
            return list;
        }

        /// <summary>
        ///  获取Symbol的bitmap预览图片。可用于获取少量有必要特殊样式预览的图片的情况 
        /// </summary>
        /// <param name="symbol">符号对象</param>
        /// <param name="iwidth"></param>
        /// <param name="iheight"></param>
        /// <returns></returns>
        public static Bitmap DrawSymbol(ISymbol symbol, int iwidth, int iheight)
        {
            //根据高宽创建图象
            Bitmap bmp = new Bitmap(iwidth, iheight);
            Graphics img = Graphics.FromImage(bmp);
            img.Clear(Color.White);
            double dpi = img.DpiX;
            IEnvelope env = new Envelope() as IEnvelope;
            env.PutCoords(0, 0, (double)bmp.Width, (double)bmp.Height);
            tagRECT deviceRect;
            deviceRect.left = 0;
            deviceRect.right = bmp.Width;
            deviceRect.top = 0;
            deviceRect.bottom = bmp.Height;
            IDisplayTransformation displayTransformation = new DisplayTransformation() as IDisplayTransformation;
            displayTransformation.VisibleBounds = env;
            displayTransformation.Bounds = env;
            displayTransformation.set_DeviceFrame(ref deviceRect);
            displayTransformation.Resolution = dpi;
            IGeometry pGeo = GetSymbolGeometry(symbol, env);
            IntPtr hdc = new IntPtr();
            hdc = img.GetHdc();
            //将符号的形状绘制到图象中
            symbol.SetupDC((int)hdc, displayTransformation);
            symbol.Draw(pGeo);
            symbol.ResetDC();
            img.ReleaseHdc(hdc);
            img.Dispose();
            return bmp;
        }

        /// <summary>
        /// 使用IStyleGalleryClass将Symbol的预览写入到图像中，速度较快，但对特殊符号不支持
        /// </summary>
        /// <param name="symbol">符号对象</param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Image DrawSymbol2(ISymbol symbol, int width, int height)
        {
            IStyleGalleryClass styleGalleryClass = null;
            if (symbol is IMarkerSymbol)
            {
                styleGalleryClass = new MarkerSymbolStyleGalleryClass();
            }
            else if (symbol is ILineSymbol)
            {
                styleGalleryClass = new LineSymbolStyleGalleryClass();
            }
            else if (symbol is IFillSymbol)
            {
                styleGalleryClass = new FillSymbolStyleGalleryClassClass();
            }
            if (styleGalleryClass != null)
            {
                Image img = new Bitmap(width, height);
                Graphics gc = Graphics.FromImage(img);
                IntPtr hdc = gc.GetHdc();
                var rect = new tagRECT();
                rect.left = 0;
                rect.top = 0;
                rect.right = width;
                rect.bottom = height;
                styleGalleryClass.Preview(symbol, hdc.ToInt32(), ref rect);
                gc.ReleaseHdc(hdc);
                gc.Dispose();
                return img;
            }
            return null;
        }
        
        /// <summary>
        /// 根据传入的符号以及外包矩形区域返回对应的几何空间实体（点，线、面）
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="envelop"></param>
        /// <returns></returns>
        private static IGeometry GetSymbolGeometry(ISymbol symbol, IEnvelope envelop)
        {
            if (symbol is IMarkerSymbol)
            {
                IArea area = (IArea)envelop;
                return area.Centroid;
            }
            else if (symbol is ILineSymbol)
            {
                IPolyline polyline = new Polyline() as IPolyline;
                var pointCollection = (IPointCollection)polyline;
                IPoint point = new ESRI.ArcGIS.Geometry.Point() as IPoint;
                object before = Type.Missing;
                object after = Type.Missing;
                point.PutCoords(envelop.XMin, (envelop.YMax + envelop.YMin) / 2.0);
                pointCollection.AddPoint(point, ref before, ref after);
                point.PutCoords((envelop.XMax ), (envelop.YMax + envelop.YMin) / 2.0);
                pointCollection.AddPoint(point, ref before, ref after);
                return polyline;
            }
            else if (symbol is IFillSymbol)
            {
                return envelop;
            }
            else if (symbol is ITextSymbol)
            {
                IArea area = (IArea)envelop;
                return area.Centroid;
            }
            return null;
        }
        
    }

    /// <summary>
    /// 当个符号子项
    /// </summary>
    public class SymbolItem
    {
        /// <summary>
        /// 符号对象
        /// </summary>
        public dynamic Symbol { get; set; }

        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 分类
        /// </summary>
        public string Category { get; set; }
    }
}
